#include <string.h>

#include <ijpegd_common.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif

static void ijpegd_icodec_param_init(ijpegd_t *h, ijpegd_icodec_param_t *param)
{
	memset(param, 0, sizeof(ijpegd_icodec_param_t));
	param->protocol = C_JPEGD;
	param->soc = h->param.soc;
	param->i_log_level = C_LOG_INFO;
	param->ckmalloc = h->param.ckmalloc;
	param->ckfree = h->param.ckfree;
	param->ckvirt_to_phys = h->param.ckvirt_to_phys;
	param->ckphys_to_virt = h->param.ckphys_to_virt;
	param->param.jpegd_param.b_tlb = h->param.b_tlb;
	param->param.jpegd_param.b_use_phy = h->param.b_use_phy;
	param->param.jpegd_param.i_devid = h->param.i_devid;

	param->param.jpegd_param.i_csp = h->param.i_csp;
	param->param.jpegd_param.i_max_width = C_ALIGN(h->param.i_max_width, 16);
	param->param.jpegd_param.i_max_height = C_ALIGN(h->param.i_max_height, 16);
}

int ijpegd_icodec_init(ijpegd_t *h)
{
	ijpegd_icodec_param_t param;

	ijpegd_icodec_param_init(h, &param);

	if ((h->icodec = hwicodec_init(&param)) == NULL) {
		ijpegd_log(h, C_LOG_ERROR, "hwicodec_init failed\n");
		goto err_hwicodec_init;
	}

	return 0;

err_hwicodec_init:
	return -1;
}

/* return bit stream size */
int ijpegd_icodec_dec(ijpegd_t *h)
{
	h->icodec_io.protocol.jpegd.fenc.yaddr = (intptr_t)h->fenc.plane[0];
	h->icodec_io.protocol.jpegd.fenc.caddr = (intptr_t)h->fenc.plane[1];
	h->icodec_io.protocol.jpegd.fbs		= h->fbs;
	h->icodec_io.protocol.jpegd.regs		= h->regs;
	h->icodec_io.protocol.jpegd.hea		= h->hea;
	h->icodec_io.protocol.jpegd.heb		= h->heb;
	h->icodec_io.protocol.jpegd.huffmin	= h->huffmin;
	h->icodec_io.protocol.jpegd.qt		= h->qt;
	h->icodec_io.protocol.jpegd.hcode		= h->hcode;
	h->icodec_io.protocol.jpegd.hlen		= h->hlen;
	h->icodec_io.protocol.jpegd.huffenc	= h->huffenc;
	h->icodec_io.bslen = 0;

	return hwicodec_process(h->icodec, &h->icodec_io);
}

void ijpegd_icodec_deinit(ijpegd_t *h)
{
	if (h->icodec != NULL) {
		hwicodec_deinit(h->icodec);
	}
}

static int ijpegd_vbinfo_check(ijpegd_t *h, const ijpegd_vbinfo_t const *vbinfo, const int num)
{
	if (((num != C_SOC_VB_MAX) || (vbinfo == NULL))
		|| ((vbinfo[C_SOC_VB_ENC].type != C_SOC_VB_ENC) || (vbinfo[C_SOC_VB_ENC].num != 1))
		|| ((vbinfo[C_SOC_VB_BS].type != C_SOC_VB_BS) || (vbinfo[C_SOC_VB_BS].num != 1))) {
		ijpegd_log(h, C_LOG_ERROR, "vbinfo checkout failed\n");
		goto err_vbinfo;
	}

	if ((vbinfo[C_SOC_VB_ENC].vb[0].yptr == 0) || (vbinfo[C_SOC_VB_ENC].vb[0].cptr == 0)
			|| (vbinfo[C_SOC_VB_ENC].vb[0].i_stride < C_ALIGN(h->param.i_max_width, 16))
			|| (vbinfo[C_SOC_VB_ENC].vb[0].i_lines < C_ALIGN(h->param.i_max_height, 16))) {
		ijpegd_log(h, C_LOG_ERROR, "vbinfo.vb.decode checkout failed\n");
		ijpegd_log(h, C_LOG_ERROR, "vbinfo[C_SOC_VB_ENC].vb[0].yptr=%p, vbinfo[C_SOC_VB_ENC].vb[0].cptr=%p, vbinfo[C_SOC_VB_ENC].vb[0].i_stride=%d, vbinfo[C_SOC_VB_ENC].vb[0].i_lines=%d\n", vbinfo[C_SOC_VB_ENC].vb[0].yptr, vbinfo[C_SOC_VB_ENC].vb[0].cptr, vbinfo[C_SOC_VB_ENC].vb[0].i_stride, vbinfo[C_SOC_VB_ENC].vb[0].i_lines);
		goto err_vbinfo_vb_enc;
	}

	if (vbinfo[C_SOC_VB_BS].vb[0].yptr == 0) {
		ijpegd_log(h, C_LOG_ERROR, "vbinfo.vb.bs checkout failed\n");
		goto err_vbinfo_vb_bs;
	}

	return 0;

err_vbinfo_vb_bs:
err_vbinfo_vb_enc:
err_vbinfo:
	return -1;
}

static inline void ijpegd_icodec_init_frame(ijpegd_vb_t *vb, ijpegd_frame_t *frame)
{
	int i = 0;
	for (i = 0; i < 2; i++) {
		frame->i_stride[i] = vb->i_stride;
		frame->i_lines[i] = vb->i_lines / ((i == 0) ? 1 : 2);
		frame->plane[i] = (pixel *)((i == 0) ? vb->yptr : vb->cptr);
	}
}

int ijpegd_icodec_request_vbinfo(ijpegd_t *h)
{
	int	vbnum = 0;

	if (hwicodec_request_vbinfo(h->icodec, &h->vbinfo, &vbnum) < 0) {
		ijpegd_log(h, C_LOG_ERROR, "icodec_request_vbinfo failed\n");
		goto err_icodec_request_vbinfo;
	}

	if (ijpegd_vbinfo_check(h, h->vbinfo, vbnum) < 0) {
		ijpegd_log(h, C_LOG_ERROR, "vbinfo_check failed\n");
		goto err_vbinfo_check;
	}

	ijpegd_icodec_init_frame(&h->vbinfo[C_SOC_VB_ENC].vb[0], &h->fenc);
	h->fbs = (uint8_t *)h->vbinfo[C_SOC_VB_BS].vb[0].yptr;

	return 0;

err_vbinfo_check:
err_icodec_request_vbinfo:
	return -1;
}

void ijpegd_icodec_release_vbinfo(ijpegd_t *h)
{
	hwicodec_release_vbinfo(h->icodec, h->vbinfo);
}
